package com.whcoding.test.common.list;

import org.apache.commons.collections.CollectionUtils;

import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * @author Manager
 * @Description 集合操作工具
 * 1、按照集合中的某个Integer、BigDecimal类型求和
 * 2、根据条件过滤集合
 * 3、根据过滤条件得到源集合中某个字段的新集合
 * @Modifier
 * @Modified Date
 * @Modified Remark
 * @Version 1.0
 **/
public class ListDataFilter {

	private static final Logger logger = LoggerFactory.getLogger(ListDataFilter.class);


	/**
	 * @param srcList   源集合
	 * @param predicate 过滤条件
	 * @param function  求和方法,即选择泛型中的Integer类型
	 * @param <T>       传入集合的泛型
	 * @return 返回求和后的值
	 * @Description Integer求和
	 */
	public static <T> Integer integerSum(List<T> srcList, Predicate<T> predicate, Function<T, Integer> function) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null || function == null) {
			return Integer.MIN_VALUE;
		}
		return srcList
				.stream()
				.filter(predicate)
				.map(function)
				.mapToInt(value -> value).sum();
	}

	/**
	 * @param srcList   源集合
	 * @param predicate 过滤条件
	 * @param function  求和方法,即选择泛型中的Double类型
	 * @param <T>       传入集合的泛型
	 * @return 返回求和后的值
	 * @Description Double求和
	 */
	public static <T> Double doubleSum(List<T> srcList, Predicate<T> predicate, Function<T, Double> function) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null || function == null) {
			return Double.MIN_VALUE;
		}

		return srcList
				.stream()
				.filter(predicate)
				.map(function)
				.mapToDouble(value -> value).sum();
	}

	/**
	 * @param srcList   源集合
	 * @param predicate 过滤条件
	 * @param function  求和方法
	 * @param <T>       源集合泛型
	 * @return 返回值
	 * @Description decimal求和，对集合中的某个BigDecimal类型进行求和
	 */
	public static <T> BigDecimal decimalSum(List<T> srcList, Predicate<T> predicate, Function<T, BigDecimal> function) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null || function == null) {
			return BigDecimal.ZERO;
		}
		return srcList
				.stream()
				.filter(predicate)
				.map(function)
				.reduce(BigDecimal.ZERO, BigDecimal::add);
	}

	/**
	 * @param srcList   源集合
	 * @param predicate 过滤条件方法
	 * @param <T>       源集合的泛型
	 * @return 返回值
	 * @Description 根据条件过滤集合，得到源集合泛型的集合
	 */
	public static <T> List<T> filterList(List<T> srcList, Predicate<T> predicate) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null) {
			return Collections.emptyList();
		}
		List<T> list = srcList.
				stream()
				.filter(predicate)
				.collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(list)) {
			return list;
		}
		return Collections.emptyList();
	}

	/**
	 * @param srcList    源集合
	 * @param predicate  过滤条件方法
	 * @param comparator 排序
	 * @param <T>        源集合的泛型
	 * @return 返回值
	 * @Description 根据条件过滤集合，得到源集合泛型的集合,并拍讯
	 */
	public static <T> List<T> filterList(List<T> srcList, Predicate<T> predicate, Comparator<T> comparator) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null) {
			return Collections.emptyList();
		}
		List<T> list = srcList.
				stream()
				.filter(predicate)
				.sorted(comparator)
				.collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(list)) {
			return list;
		}
		return Collections.emptyList();
	}

	/**
	 * @param srcList  源集合
	 * @param function 过滤条件方法
	 * @param <T>      源集合的泛型
	 * @param <S>      返回集合的泛型
	 * @return 返回值
	 * @Description 根据条件过滤集合数据，得到想要的泛型集合
	 */
	public static <T, S> List<S> filterData(List<T> srcList, Function<T, S> function) {
		if (CollectionUtils.isEmpty(srcList) || function == null) {
			return Collections.emptyList();
		}
		return filterData(srcList, T -> T != null, function);
	}

	/**
	 * @param srcList   源集合
	 * @param predicate 过滤条件方法
	 * @param function  生成返回集合的方法
	 * @param <T>       源集合的泛型
	 * @param <S>       返回集合的泛型
	 * @return 返回值
	 * @Description 根据条件过滤集合数据，得到想要的泛型集合
	 */
	public static <T, S> List<S> filterData(List<T> srcList, Predicate<T> predicate, Function<T, S> function) {
		if (CollectionUtils.isEmpty(srcList) || predicate == null || function == null) {
			return Collections.emptyList();
		}
		List<S> list = srcList.
				stream()
				.filter(predicate)
				.map(function)
				.distinct()
				.collect(Collectors.toList());
		if (CollectionUtils.isNotEmpty(list)) {
			return list;
		}
		return Collections.emptyList();
	}

	/**
	 * @param srcList  源集合
	 * @param function 分组的方法
	 * @param <T>      源集合泛型
	 * @param <K>      分组方法的泛型
	 * @return
	 * @Description 对集合进行分组
	 */
	public static <T, K> Map<K, List<T>> groupingList(List<T> srcList, Function<T, K> function) {
		if (CollectionUtils.isEmpty(srcList) || function == null) {
			return null;
		}
		return groupingList(srcList, function, Collectors.toList());
	}

	/**
	 * @param srcList    源集合
	 * @param function   分组的方法
	 * @param downstream 数据收集器
	 * @param <T>        源集合泛型
	 * @param <K>        分组方法的泛型
	 * @param <A>
	 * @param <D>
	 * @return
	 * @Description 对集合进行分组
	 */
	public static <T, K, A, D> Map<K, D> groupingList(List<T> srcList, Function<T, K> function,
													  Collector<? super T, A, D> downstream) {
		if (CollectionUtils.isEmpty(srcList) || function == null || downstream == null) {
			return null;
		}
		return groupingList(srcList, function, HashMap::new, downstream);
	}

	/**
	 * 对集合进行分组
	 *
	 * @param srcList    源集合
	 * @param function   分组的方法
	 * @param mapFactory 分组器
	 * @param downstream 数据收集器
	 * @param <T>        源集合泛型
	 * @param <K>        分组方法的泛型
	 * @param <D>
	 * @param <A>
	 * @param <M>
	 * @return
	 */
	public static <T, K, D, A, M extends Map<K, D>> Map<K, D> groupingList(List<T> srcList, Function<T, K> function,
																		   Supplier<M> mapFactory, Collector<? super T, A, D> downstream) {
		if (CollectionUtils.isEmpty(srcList) || function == null || downstream == null || mapFactory == null) {
			return new HashMap<>(1);
		}
		return srcList.stream().collect(Collectors.groupingBy(function, mapFactory, downstream));
	}


	/**
	 * 获取list中存放的最后一个元素
	 *
	 * @param list
	 * @param <T>
	 * @return
	 */
	public static <T> T getLastElement(List<T> list) {
		return list.get(list.size() - 1);
	}


	/**
	 * Set去重代码示例
	 *
	 * @param data
	 * @param <T>
	 * @return
	 */
	public static <T> Set<T> removeDuplicateBySet(List<T> data) {

		if (org.springframework.util.CollectionUtils.isEmpty(data)) {
			return new HashSet<>();
		}
		return new HashSet<>(data);
	}

	/**
	 * List 方法去重 推荐优先
	 *
	 * @param list
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> removeDuplicates(List<T> list) {
		return new ArrayList(new LinkedHashSet(list));
	}

	/**
	 * List 去重代码示例
	 *
	 * @param data
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> removeDuplicateByList(List<T> data) {
		if (org.springframework.util.CollectionUtils.isEmpty(data)) {
			return new ArrayList<>();

		}
		List<T> result = new ArrayList<>(data.size());
		for (T current : data) {
			if (!result.contains(current)) {
				result.add(current);
			}
		}
		return result;
	}

	/**
	 * 父类集合转成子类集合集合通用方法(子类集合接收父类集合)
	 *
	 * @param list 父类集合
	 * @param <T>  子类
	 * @param <E>  父类
	 * @return
	 */
	public static <T, E> List<T> chang2ChildClassList(List<E> list) {
		List<T> alist = new ArrayList<>();
		for (E o : list) {
			alist.add((T) o);
		}
		return alist;
	}


	/**
	 * 判断是否有重复的数据
	 *
	 * @param list 数据源
	 * @return
	 */
	public static <T> boolean isRepetition(List<T> list) {
		long count = list.stream().distinct().count();
		boolean isRepeat = count < list.size();
		return isRepeat;
	}

	/**
	 * 进行分页
	 * @param list
	 * @param page
	 * @param size
	 * @return
	 */
	public static <T> List<T> getPageResult(List<T> list, int page, int size) {
		//模拟分页效果
		return list.stream().skip((page - 1) * size)
				.limit(size)
				.collect(Collectors.toList());
	}

}
